/*
 *  SimpleNoteGenerator.cpp
 *  SoundController0002
 *
 *  Created by jiro on 10/09/20.
 *  Copyright 2010 jiro music. All rights reserved.
 *
 */

#include "SoundGenerator.h"
#include "NoteInfo.h"
#include "WaveTableFactory.h"

namespace sc
{
	//	recommended
	std::vector< const SoundElement32* > SoundGenerator::Generate( const std::vector< NoteInfo >& noteInfos )
	{
		size_t noteCount = noteInfos.size();
		std::vector< const SoundElement32* > notes( noteCount );
		for ( size_t i = 0; i < noteCount; i++ )
		{
			notes[ i ] = SoundGenerator::Generate( noteInfos[ i ] ); 
		}
		return notes;
	}
	
	//	recommended
	const SoundElement32* SoundGenerator::Generate( const NoteInfo& noteInfo )
	{
		const WaveTable* dynamicsTable;
		const WaveTable& soundTable = WaveTableFactory::Create( WaveTable::Type_Sine, noteInfo.frequency, 1.0, noteInfo.phaseShift );
		if ( noteInfo.dynamicsCurve->IsNull() )
		{
			dynamicsTable = & WaveTableFactory::Create( WaveTable::Type_Sine, 1.0 / ( 2.0 * noteInfo.duration ), noteInfo.dynamics );
		}
		else
		{
			dynamicsTable = & WaveTableFactory::Create( * noteInfo.dynamicsCurve, noteInfo.dynamics );
		}
		const SoundElement32* element = SoundElementFactory32::Create( soundTable, * dynamicsTable, noteInfo.duration );
		return element;
	}

	//	deprecated
	std::vector< const SoundElement32* > SoundGenerator::GenerateChord( 
			const std::vector< Note::MidiNumber >& numbers, double noteLength, double singleNoteDynamics )
	{
		std::vector< const SoundElement32* > chord( numbers.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = SoundGenerator::Generate( numbers[ i ], noteLength, singleNoteDynamics );
		}
		return chord;
	}

	//	deprecated
	std::vector< const SoundElement32* > SoundGenerator::GenerateChord( 
			const std::vector< Note::MidiNumber >& numbers, const std::vector< double >& noteLengths, const std::vector< double >& dynamics )
	{
		assert( numbers.size() == noteLengths.size() && numbers.size() == dynamics.size() );
		std::vector< const SoundElement32* > chord( numbers.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord.push_back( SoundGenerator::Generate( numbers[ i ], noteLengths[ i	], dynamics[ i ] ) );
		}
		return chord;
	}

	//	deprecated
	std::vector< const SoundElement32* > SoundGenerator::GenerateChord( 
			const std::vector< double >& freqs, double noteLength, double singleNoteDynamics )
	{
		std::vector< const SoundElement32* > chord( freqs.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = SoundGenerator::Generate( freqs[ i ], noteLength, singleNoteDynamics );
		}
		return chord;
	}

	//	deprecated
	std::vector< const SoundElement32* > SoundGenerator::GenerateChord( 
			const std::vector< double >& freqs, const std::vector< double >& noteLengths, const std::vector< double >& dynamics )
	{
		assert( freqs.size() == noteLengths.size() && freqs.size() == dynamics.size() );
		std::vector< const SoundElement32* > chord( freqs.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = SoundGenerator::Generate( freqs[ i ], noteLengths[ i ], dynamics[ i ] );
		}
		return chord;
	}

	const SoundElement32* SoundGenerator::GenerateWithDynamicsTable( double frequency, double duration, double adjuster )
	{
		const WaveTable& dynamicsTable = WaveTableFactory::Create( WaveTable::Type_Sine, 1.0 / ( 2.0 * duration ), adjuster );
		const WaveTable& soundTable = WaveTableFactory::Create( WaveTable::Type_Sine, frequency, 1.0 );
		const SoundElement32* element = SoundElementFactory32::Create( soundTable, dynamicsTable, duration );
		return element;
	}

	const SoundElement32* SoundGenerator::GenerateWithDynamicsTable( Note::MidiNumber number, double noteLength, double adjuster )
	{
		double noteFreq_Hz = WellTemperament::GetFrequency( number );
		return SoundGenerator::Generate( noteFreq_Hz, noteLength, adjuster );
	}

	std::vector< const SoundElement32* > SoundGenerator::GenerateChordWithDynamicsTable( 
			const std::vector< Note::MidiNumber >& numbers, double duration, double adjuster )
	{
		std::vector< const SoundElement32* > chord( numbers.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = GenerateWithDynamicsTable( numbers[ i ], duration, adjuster );
		}
		return chord;
	}

	std::vector< const SoundElement32* > SoundGenerator::GenerateChordWithDynamicsTable( 
			const std::vector< Note::MidiNumber >& numbers, const std::vector< double >& durations, const std::vector< double >& dynamics )
	{
		std::vector< const SoundElement32* > chord( numbers.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = GenerateWithDynamicsTable( numbers[ i ], durations[ i ], dynamics[ i ] );
		}
		return chord;
	}

	std::vector< const SoundElement32* >SoundGenerator::GenerateChordWithDynamicsTable( 
			const std::vector< double >& freqs, double duration, double adjuster )
	{
		std::vector< const SoundElement32* > chord( freqs.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = GenerateWithDynamicsTable( freqs[ i ], duration, adjuster );
		}
		return chord;
	}

	std::vector< const SoundElement32* > SoundGenerator::GenerateChordWithDynamicsTable( 
			const std::vector< double >& freqs, const std::vector< double >& noteLengths, const std::vector< double >& dynamics )
	{
		std::vector< const SoundElement32* > chord( freqs.size() );
		for ( size_t i = 0; i < chord.size(); i++ ) {
			chord[ i ] = GenerateWithDynamicsTable( freqs[ i ], noteLengths[ i ], dynamics[ i ] );
		}
		return chord;
	}

	void SoundGenerator::GenerateChordWithSineDynamicsTable( 
		const std::vector< NoteInfo >& noteInfos,
		std::vector< const SoundElement32* >& chord )
	{
		chord.resize( noteInfos.size() );
		size_t count = noteInfos.size();
		for ( size_t i = 0; i < count; i++ ) {
			const NoteInfo& info = noteInfos[ i ];
			const WaveFunction& func = WaveFunctionFactory::CreateXSinX( 1, 2 * info.duration, true );
			const WaveTable& dynamicsTable = WaveTableFactory::Create( func, info.dynamics );
			const WaveTable& soundTable = WaveTableFactory::CreateSin( info.frequency, 0.0, 1.0 );
			chord[ i ] = SoundElementFactory32::Create( soundTable, dynamicsTable, info.duration );
//			chord[ i ] = GenerateWithDynamicsTable( double frequency, double duration, double adjuster )	バグっている様なので使わん。
		}
	}

	// deprecated
	const SoundElement32* SoundGenerator::Generate( Note::Id noteId, int octaveNumber, double noteLength, double maxDynamics )
	{
		double noteFreq_Hz = WellTemperament::GetFrequency( noteId, octaveNumber );
		return SoundGenerator::Generate( noteFreq_Hz, noteLength, maxDynamics );
	}
	
	// deprecated
	const SoundElement32* SoundGenerator::Generate( double noteFrequency, double noteLength, double maxDynamics )
	{
		bool noteLengthIsLongEnough = noteLength > 1.0 / 8.0;
		const double attackTime = noteLengthIsLongEnough ? 1 / 16. : noteLength / 4.0;
		const double decayTime = noteLengthIsLongEnough ? attackTime : noteLength / 4.0;
		const double sustainTime = noteLength - 3 * attackTime;
		const double releaseTime = attackTime;

		double attackEndTime = attackTime;
		double decayEndTime = attackEndTime + decayTime;
		double sustainEndTime = decayEndTime + sustainTime;
		double releaseEndTime = sustainEndTime + releaseTime;
		double attackDynamics = maxDynamics;
		double decayDynamics = 0.75 * maxDynamics;
		const Line* attackLine	= & LineFactory::Create( Line::Type_Straight, 0.0,            0.0,            attackEndTime,  attackDynamics );
		const Line* decayLine	= & LineFactory::Create( Line::Type_Straight, attackEndTime,  attackDynamics, decayEndTime,   decayDynamics );
		const Line* sustainLine = & LineFactory::Create( Line::Type_Straight, decayEndTime,   decayDynamics,	sustainEndTime, decayDynamics );
		const Line* releaseLine = & LineFactory::Create( Line::Type_Straight, sustainEndTime,	decayDynamics,	releaseEndTime, 0.0 );
		const WaveTable& noteTable = WaveTableFactory::Create( WaveTable::Type_Sine, noteFrequency );

		const SoundElement32* element = 
			SoundElementFactory32::Create( attackEndTime, attackLine, decayEndTime, decayLine,
				sustainEndTime, sustainLine, releaseEndTime, releaseLine, noteTable );
		return element;
	}

	// deprecated
	const SoundElement32* SoundGenerator::Generate( Note::MidiNumber number, double noteLength, double maxDynamics )
	{
		double noteFreq_Hz = WellTemperament::GetFrequency( number );
		return SoundGenerator::Generate( noteFreq_Hz, noteLength, maxDynamics );
	}


}